package com.easygoods.service;

import com.bestvike.linq.Linq;
import com.bestvike.stone.core.collection.ArrayUtils;
import com.bestvike.stone.core.collection.CollectionUtils;
import com.bestvike.stone.core.lang.Convert;
import com.bestvike.stone.core.lang.RandomUtils;
import com.bestvike.stone.core.lang.StringUtils;
import com.bestvike.stone.core.serialization.JsonSerializer;
import com.bestvike.stone.core.time.DateUtils;
import com.bestvike.stone.spring.exception.BusinessException;
import com.bestvike.stone.spring.exception.ErrorCode;
import com.bestvike.stone.spring.mail.bugreport.BugReportLevel;
import com.bestvike.stone.spring.mail.bugreport.BugReportUtils;
import com.bestvike.stone.spring.page.PageableResponse;
import com.bestvike.stone.spring.service.BaseService;
import com.easygoods.bean.OrderAttach;
import com.easygoods.bean.OrderBean;
import com.easygoods.bean.PayOrderBean;
import com.easygoods.dao.ExpressInfoDao;
import com.easygoods.dao.GoodsSkuDao;
import com.easygoods.dao.GoodsSpuDao;
import com.easygoods.dao.OrderCouponDao;
import com.easygoods.dao.OrderGoodsDao;
import com.easygoods.dao.OrderInfoDao;
import com.easygoods.dao.OrderRecordDao;
import com.easygoods.dao.OrderRefundFileDao;
import com.easygoods.dao.PayRecordDao;
import com.easygoods.dao.StockLockDao;
import com.easygoods.entity.ExpressInfo;
import com.easygoods.entity.GoodsSku;
import com.easygoods.entity.MemberAddress;
import com.easygoods.entity.MemberCoupon;
import com.easygoods.entity.MemberInfo;
import com.easygoods.entity.MerchantInfo;
import com.easygoods.entity.OrderCoupon;
import com.easygoods.entity.OrderGoods;
import com.easygoods.entity.OrderInfo;
import com.easygoods.entity.OrderRecord;
import com.easygoods.entity.OrderRefundFile;
import com.easygoods.entity.PayRecord;
import com.easygoods.entity.StockLock;
import com.easygoods.entity.StoreInfo;
import com.easygoods.enums.AddressType;
import com.easygoods.enums.OrderState;
import com.easygoods.enums.PayChannel;
import com.easygoods.enums.YNEnum;
import com.easygoods.external.wechat.pay.respon.WeChatOrderCreateResponse;
import com.easygoods.properties.OrderProperties;
import com.easygoods.request.OrderCommitRequest;
import com.easygoods.request.OrderCommitRequestSku;
import com.easygoods.request.OrderListRequest;
import com.easygoods.request.OrderSendRequest;
import com.easygoods.request.OrderTrailRequest;
import com.easygoods.response.OrderCommitResponse;
import com.easygoods.response.OrderDetailResponse;
import com.easygoods.response.OrderDetailResponseItem;
import com.easygoods.response.OrderListResponse;
import com.easygoods.response.OrderTrailResponse;
import com.easygoods.shiro.auth.UserAuth;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import tk.mybatis.mapper.entity.Example;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * @author zhq
 * @date 2019/1/2 15:46
 */
@Service
public class OrderService extends BaseService {
    @Autowired
    private OrderInfoDao orderInfoDao;
    @Autowired
    private GoodsSkuDao goodsSkuDao;
    @Autowired
    private StockLockDao stockLockDao;
    @Autowired
    private OrderGoodsDao orderGoodsDao;
    @Autowired
    private MemberService memberService;
    @Autowired
    private PointService pointService;
    @Autowired
    private GoodsService goodsService;
    @Autowired
    private StockService stockService;
    @Autowired
    private CouponService couponService;
    @Autowired
    private OrderCouponDao orderCouponDao;
    @Autowired
    private AddressService addressService;
    @Autowired
    private OrderRecordDao orderRecordDao;
    @Autowired
    private CashService cashService;
    @Autowired
    private PayRecordDao payRecordDao;
    @Autowired
    private WeChatService weChatService;
    @Autowired
    private FileService fileService;
    @Autowired
    private OrderRefundFileDao orderRefundFileDao;
    @Autowired
    private MerchantService merchantService;
    @Autowired
    private StoreService storeService;
    @Autowired
    private ExpressInfoDao expressInfoDao;
    @Autowired
    private GoodsSpuDao goodsSpuDao;
    @Autowired
    private MissionService missionService;
    @Autowired
    private OrderProperties orderProperties;
    @Autowired
    private ConfigService configService;
    @Autowired
    private HotSpuService hotSpuService;


    //生成订单号
    private static String genOrderId() {
        return DateUtils.nowString("yyyyMMddHHmmssSSS") + StringUtils.leftPad(String.valueOf(RandomUtils.nextInt(1, 99999)), 5, '0');
    }

    //使用代金券
    private BigDecimal consumeCouponList(String memberId, List<String> couponIdList, String orderId) {
        if (CollectionUtils.isEmpty(couponIdList)) {
            this.log.info("该会员没有使用代金券");
            return BigDecimal.ZERO;
        }

        BigDecimal totalCouponAmount = BigDecimal.ZERO;
        for (String couponId : couponIdList) {
            MemberCoupon coupon = this.couponService.consumeCoupon(memberId, couponId, orderId);//使用代金券
            totalCouponAmount = totalCouponAmount.add(coupon.getAmount());//计算合计

            //订单代金券
            OrderCoupon orderCoupon = new OrderCoupon();
            orderCoupon.setId(RandomUtils.randomUUID());
            orderCoupon.setOrderId(orderId);
            orderCoupon.setCouponId(coupon.getId());
            orderCoupon.setCouponAmount(coupon.getAmount());
            orderCoupon.beforeInsert();
            this.orderCouponDao.insert(orderCoupon);
        }
        return totalCouponAmount;
    }

    //试算代金券
    private BigDecimal computeCouponList(String memberId, List<String> couponIdList) {
        if (CollectionUtils.isEmpty(couponIdList))
            return BigDecimal.ZERO;

        BigDecimal totalCouponAmount = BigDecimal.ZERO;
        for (String couponId : couponIdList) {
            MemberCoupon coupon = this.couponService.getValidMemberCoupon(memberId, couponId);//获取代金券
            totalCouponAmount = totalCouponAmount.add(coupon.getAmount());//计算合计
        }
        return totalCouponAmount;
    }

    //获取订单总金额、订单总商品件数，新增商品锁定表、订单商品表
    private OrderBean consumeGoodsList(List<OrderCommitRequestSku> skuList, String orderId, int memberGrade) {
        String merchantId = null;
        BigDecimal totalOrderAmount = BigDecimal.ZERO;
        BigDecimal totalMemberAmount = BigDecimal.ZERO;
        int pointValue = 0;
        int itemCount = 0;
        for (OrderCommitRequestSku sku : Linq.asEnumerable(skuList).orderBy(OrderCommitRequestSku::getSkuId)) {
            //查询商品信息
            GoodsSku goodsSku = this.goodsSkuDao.findMerchantSku(sku.getMerchantId(), sku.getSkuId());
            if (goodsSku == null)
                throw new BusinessException(ErrorCode.ERROR_SERVER, "无效的商品");
            //锁定库存
            String orderGoodsId = RandomUtils.randomUUID();
            String stockLockId = this.stockService.lockStock(goodsSku, sku.getNum(), "用户提交订单，生成订单", orderId, orderGoodsId);
            //计算会员价
            BigDecimal memberPrice = this.goodsService.getMemberPrice(memberGrade, goodsSku.getMinPrice(), goodsSku.getOriginPrice());
            this.log.info("会员价memberPrice:" + memberGrade);
            //生成订单商品表并入库
            OrderGoods orderGoods = new OrderGoods();
            orderGoods.setId(orderGoodsId);
            orderGoods.setOrderId(orderId);
            orderGoods.setSkuId(sku.getSkuId());
            orderGoods.setSkuNo(goodsSku.getSkuNo());
            orderGoods.setSkuName(goodsSku.getSkuName());
            orderGoods.setSpuId(goodsSku.getSpuId());
            orderGoods.setLockId(stockLockId);
            orderGoods.setOriginPrice(goodsSku.getOriginPrice());
            orderGoods.setMinPrice(goodsSku.getMinPrice());
            orderGoods.setMemberPrice(memberPrice);
            orderGoods.setNum(sku.getNum());
            orderGoods.beforeInsert();
            int orderGoodsNum = this.orderGoodsDao.insert(orderGoods);
            if (orderGoodsNum != 1) {
                throw new BusinessException(ErrorCode.ERROR_SERVER, "订单商品表记录入库失败");
            }
            //商户
            if (StringUtils.isEmpty(merchantId))
                merchantId = sku.getMerchantId();
            else if (!StringUtils.equals(sku.getMerchantId(), merchantId))
                throw new BusinessException(ErrorCode.ERROR_SERVER, "不支持跨店下单");
            //原价总金额
            BigDecimal goodsNum = Convert.toDecimal(sku.getNum());
            totalOrderAmount = totalOrderAmount.add(goodsSku.getOriginPrice().multiply(goodsNum));
            //会员价总金额
            totalMemberAmount = totalMemberAmount.add(memberPrice.multiply(goodsNum));
            //sku 数量
            itemCount += sku.getNum();
            //积分
            pointValue += this.pointService.computeGoodsPointValue(memberPrice) * sku.getNum();
        }
        //商户
        if (StringUtils.isEmpty(merchantId)) {
            this.log.warn("所有商品的 merchantId 都为空");
            throw new BusinessException(ErrorCode.ERROR_SERVER, "商户不能为空");
        }
        OrderBean orderBean = new OrderBean();
        orderBean.setMerchantId(merchantId);
        orderBean.setItemCount(itemCount);
        orderBean.setPointValue(pointValue);
        orderBean.setTotalOrderAmount(this.configService.roundAmount(totalOrderAmount));
        orderBean.setTotalMemberAmount(this.configService.roundAmount(totalMemberAmount));
        orderBean.setDeliveryFee(BigDecimal.ZERO);
        orderBean.assertValid();//断言
        return orderBean;
    }

    //试算商品金额
    private OrderBean computeGoodsList(List<OrderCommitRequestSku> skuList, int memberGrade) {
        BigDecimal totalOrderAmount = BigDecimal.ZERO;
        BigDecimal totalMemberAmount = BigDecimal.ZERO;
        int pointValue = 0;
        int itemCount = 0;
        for (OrderCommitRequestSku sku : Linq.asEnumerable(skuList).orderBy(OrderCommitRequestSku::getSkuId)) {
            //查询商品信息
            GoodsSku goodsSku = this.goodsSkuDao.selectByPrimaryKey(sku.getSkuId());
            if (goodsSku == null)
                throw new BusinessException(ErrorCode.ERROR_SERVER, "不明确的商品");
            BigDecimal memberPrice = this.goodsService.getMemberPrice(memberGrade, goodsSku.getMinPrice(), goodsSku.getOriginPrice());
            //原价总金额
            BigDecimal goodsNum = Convert.toDecimal(sku.getNum());
            totalOrderAmount = totalOrderAmount.add(goodsSku.getOriginPrice().multiply(goodsNum));
            //会员价总金额
            totalMemberAmount = totalMemberAmount.add(memberPrice.multiply(goodsNum));
            //sku 数量
            itemCount += sku.getNum();
            //积分
            pointValue += this.pointService.computeGoodsPointValue(memberPrice) * sku.getNum();
        }
        OrderBean orderBean = new OrderBean();
        orderBean.setItemCount(itemCount);
        orderBean.setPointValue(pointValue);
        orderBean.setTotalOrderAmount(totalOrderAmount);
        orderBean.setTotalMemberAmount(totalMemberAmount);
        orderBean.setDeliveryFee(BigDecimal.ZERO);
        orderBean.assertValid();//断言
        return orderBean;
    }

    //根据orderId获取OrderInfo
    private OrderInfo getOrderInfo(String orderId) {
        OrderInfo orderInfo = this.orderInfoDao.selectByPrimaryKey(orderId);
        if (orderInfo == null) {
            this.log.warn("订单不存在");
            throw new BusinessException(ErrorCode.ERROR_SERVER, "无效的订单,请刷新");
        }
        return orderInfo;
    }

    //根据orderId查询订单,非 null
    private OrderInfo getOrderInfoByState(String orderId, OrderState... orderStates) {
        OrderInfo orderInfo = this.getOrderInfo(orderId);
        //验证订单状态
        OrderState state = Convert.toType(orderInfo.getState(), OrderState.class);
        if (!ArrayUtils.contains(orderStates, state)) {
            this.log.warn(String.format("订单状态不是 %s 状态 orderId: %s", StringUtils.join(",", Linq.asEnumerable(orderStates).select(Enum::name)), orderId));
            throw new BusinessException(ErrorCode.ERROR_SERVER, "订单状态错误, 请刷新");
        }
        return orderInfo;
    }

    //获取订单商品列表
    private List<OrderGoods> getOrderGoodsList(String orderId) {
        Example orderGoodsExample = new Example(OrderGoods.class);
        orderGoodsExample.createCriteria().andEqualTo(OrderGoods.ORDER_ID, orderId);
        final List<OrderGoods> orderGoodsList = this.orderGoodsDao.selectByExample(orderGoodsExample);
        if (CollectionUtils.isEmpty(orderGoodsList)) {
            this.log.warn("订单没有商品");
            throw new BusinessException(ErrorCode.ERROR_SERVER, "无效的订单,请刷新");
        }
        return orderGoodsList;
    }

    //获取订单的代金券列表
    private List<OrderCoupon> getOrderCouponList(String orderId) {
        Example orderCouponExample = new Example(OrderCoupon.class);
        orderCouponExample.createCriteria().andEqualTo(OrderCoupon.ORDER_ID, orderId);
        return this.orderCouponDao.selectByExample(orderCouponExample);
    }

    //修改订单表状态
    private void modifyOrderState(String orderId, OrderState prevState, OrderState state, boolean setAfterSales) {
        final Example updateOrderExample = new Example(OrderInfo.class);
        updateOrderExample.createCriteria().andEqualTo(OrderInfo.ID, orderId)
                .andEqualTo(OrderInfo.STATE, prevState.name());

        OrderInfo orderInfoUpdate = new OrderInfo();
        orderInfoUpdate.setState(state.name());
        if (setAfterSales)
            orderInfoUpdate.setAfterSales(YNEnum.Y.name());
        orderInfoUpdate.beforeUpdate();
        int orderUpdateNum = this.orderInfoDao.updateByExampleSelective(orderInfoUpdate, updateOrderExample);
        if (orderUpdateNum != 1) {
            this.log.error(String.format("更新订单表状态到%s失败", state.name()));
            throw new BusinessException(ErrorCode.ERROR_SERVER, "更新订单状态失败");
        }
    }

    //保存订单退款图片
    private void saveRefundFileList(String orderId, List<String> fileIdList) {
        if (CollectionUtils.isEmpty(fileIdList))
            return;
        for (String fileId : fileIdList) {
            if (!this.fileService.existsFile(fileId)) {
                this.log.warn("退款文件为上传完 orderId:" + orderId);
                throw new BusinessException(ErrorCode.ERROR_SERVER, "请附件上传完后再提交");
            }
            OrderRefundFile orderRefundFile = new OrderRefundFile();
            orderRefundFile.setId(RandomUtils.randomUUID());
            orderRefundFile.setOrderId(orderId);
            orderRefundFile.setFileId(fileId);
            orderRefundFile.beforeInsert();
            final int cont = this.orderRefundFileDao.insert(orderRefundFile);
            if (cont != 1) {
                this.log.error("insert 订单退款图片失败 orderId:" + orderId);
                throw new BusinessException(ErrorCode.ERROR_SERVER, "提交失败,请重试");
            }
        }
    }

    //是否首次购买
    private boolean isFirstBuy(String memberId) {
        return this.orderInfoDao.isFirstBuy(memberId);
    }

    //订单试算
    @Transactional
    public OrderTrailResponse trailOrder(OrderTrailRequest request) {
        if (CollectionUtils.isEmpty(request.getSkuList())) {
            OrderTrailResponse response = new OrderTrailResponse();
            response.setTotalAmount(BigDecimal.ZERO);
            response.setTotalMemberAmount(BigDecimal.ZERO);
            response.setDeliveryFee(BigDecimal.ZERO);
            response.setPayAmount(BigDecimal.ZERO);
            return response;
        }
        final UserAuth userAuth = this.getAuth();
        String memberId = userAuth.getMemberId();
        //获取用户信息记录
        MemberInfo memberInfo = this.memberService.getMemberInfo(memberId);
        //计算商品金额
        final OrderBean orderBean = this.computeGoodsList(request.getSkuList(), memberInfo.getGrade());
        //计算代金券
        BigDecimal totalCouponAmount = this.computeCouponList(memberId, request.getCouponList());
        //计算应付
        BigDecimal payAmount = totalCouponAmount.compareTo(orderBean.getTotalMemberAmount()) >= 0
                ? orderBean.getDeliveryFee()
                : orderBean.getTotalMemberAmount().subtract(totalCouponAmount).add(orderBean.getDeliveryFee());
        //返回
        OrderTrailResponse response = new OrderTrailResponse();
        response.setTotalAmount(orderBean.getTotalOrderAmount());
        response.setTotalMemberAmount(orderBean.getTotalMemberAmount());
        response.setDeliveryFee(orderBean.getDeliveryFee());
        response.setPayAmount(payAmount);
        return response;
    }

    //提交订单(禁止跨商户)
    @Transactional
    public OrderCommitResponse commitOrder(OrderCommitRequest request) {
        final UserAuth userAuth = this.getAuth();
        String memberId = userAuth.getMemberId();//用户id
        String merchantId = request.getSkuList().get(0).getMerchantId();
        MemberInfo memberInfo = this.memberService.getMemberInfo(memberId);//用户信息
        MemberInfo refMemberInfo = this.memberService.getMemberInfo(memberInfo.getRefMemberId());//该用户的推荐人信息
        StoreInfo storeInfo = this.memberService.getStoreInfo(memberId);//用户的store
        MerchantInfo merchantInfo = this.merchantService.getMerchantInfo(merchantId);//商户信息
        //锁定库存 (获取订单总金额、会员总金额、订单中商品件数、该笔订单的积分数)
        String orderId = genOrderId();
        OrderBean orderBean = this.consumeGoodsList(request.getSkuList(), orderId, memberInfo.getGrade());
        //使用代金券
        BigDecimal totalCouponAmount = this.consumeCouponList(memberId, request.getCouponList(), orderId);
        //支付金额,状态计算
        BigDecimal payAmount = totalCouponAmount.compareTo(orderBean.getTotalMemberAmount()) >= 0
                ? orderBean.getDeliveryFee()
                : orderBean.getTotalMemberAmount().subtract(totalCouponAmount).add(orderBean.getDeliveryFee());

        OrderState orderState = payAmount.compareTo(BigDecimal.ZERO) == 0//如果不需要支付则状态直接为待发货
                ? OrderState.ToSend
                : OrderState.ToPay;
        //创建支付渠道的订单
        String payTradeNoPre = null;//预交易号
        Object payArgs = null;//交易参数
        OrderAttach orderAttach = new OrderAttach(merchantInfo.getId(), merchantInfo.getMerchantName());
        if (orderState == OrderState.ToPay) {
            if (userAuth.getChannel() == null)
                throw new BusinessException(ErrorCode.ERROR_SERVER, "不支持的渠道");
            switch (userAuth.getChannel()) {
                case WeChat:
                    final WeChatOrderCreateResponse wechatOrder = this.weChatService.createOrder(userAuth.getOpenId(), orderId, payAmount, JsonSerializer.serialize(orderAttach));
                    payTradeNoPre = wechatOrder.getPrepay_id();
                    payArgs = this.weChatService.signPay(payTradeNoPre);
                    break;
                case AliPay:
                    throw new BusinessException(ErrorCode.ERROR_SERVER, "不支持的渠道,敬请期待");
                default:
                    throw new BusinessException(ErrorCode.ERROR_SERVER, "不支持的渠道");
            }
        }
        //库存足够，开始创建订单
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderId);//主键
        orderInfo.setMerchantId(orderBean.getMerchantId());//商户
        orderInfo.setStoreId(storeInfo.getId());//购买人 store
        orderInfo.setMemberId(memberId);
        orderInfo.setMemberMobile(memberInfo.getMobile());
        orderInfo.setRefMemberId(refMemberInfo == null ? null : refMemberInfo.getId());//邀请人
        orderInfo.setRefMemberMobile(refMemberInfo == null ? null : refMemberInfo.getMobile());//邀请人手机号
        //数量金额
        orderInfo.setSkuCount(request.getSkuList().size());
        orderInfo.setItemCount(orderBean.getItemCount());
        orderInfo.setPointValue(orderBean.getPointValue());
        orderInfo.setTotalOrderAmount(orderBean.getTotalOrderAmount());//原价合计
        orderInfo.setTotalMemberAmount(orderBean.getTotalMemberAmount());//会员价合计
        orderInfo.setTotalCouponAmount(totalCouponAmount);//计算所有代金券的金额
        //支付金额计算(如果代金券金额以足以支付会员金额,则支付金额为 0)
        orderInfo.setPayChannel(userAuth.getChannel().getPayChannel().name());//支付渠道
        orderInfo.setPayTradeNoPre(payTradeNoPre);//支付交易号
        orderInfo.setPayOpenId(userAuth.getOpenId());//支付人
        orderInfo.setPayAmount(payAmount);//应支付金额
        orderInfo.setPayTradeNo(null);//实际交易号
        orderInfo.setPayTime(null);//支付时间
        orderInfo.setPayFinished(YNEnum.N.name());//是否支付
        //快递
        orderInfo.setDeliveryType(request.getDeliveryType().name());
        orderInfo.setDeliveryFee(orderBean.getDeliveryFee());
        orderInfo.setExpressId(null);
        orderInfo.setExpressOrderId(null);
        orderInfo.setExpressOrderState(null);
        orderInfo.setExpressTraceTime(null);
        //发货地址
        String sendAddressId = request.getSendAddressId();
        if (StringUtils.isEmpty(sendAddressId)) {
            this.log.info("发货人地址为空");
            orderInfo.setSendProvinceId(merchantInfo.getProvinceId());
            orderInfo.setSendProvinceName(merchantInfo.getProvinceName());
            orderInfo.setSendCityId(merchantInfo.getCityId());
            orderInfo.setSendCityName(merchantInfo.getCityName());
            orderInfo.setSendCountyId(merchantInfo.getCountyId());
            orderInfo.setSendCountyName(merchantInfo.getCountyName());
            orderInfo.setSendTownId(merchantInfo.getTownId());
            orderInfo.setSendTownName(merchantInfo.getTownName());
            orderInfo.setSendAddress(merchantInfo.getAddress());
            orderInfo.setSendPerson(merchantInfo.getPerson());
            orderInfo.setSendMobile(merchantInfo.getMobile());
        } else {
            MemberAddress sendAddress = this.addressService.getAddress(sendAddressId, memberId, AddressType.Send);
            orderInfo.setSendProvinceId(sendAddress.getProvinceId());
            orderInfo.setSendProvinceName(sendAddress.getProvinceName());
            orderInfo.setSendCityId(sendAddress.getCityId());
            orderInfo.setSendCityName(sendAddress.getCityName());
            orderInfo.setSendCountyId(sendAddress.getCountyId());
            orderInfo.setSendCountyName(sendAddress.getCountyName());
            orderInfo.setSendTownId(sendAddress.getTownId());
            orderInfo.setSendTownName(sendAddress.getTownName());
            orderInfo.setSendAddress(sendAddress.getDetailedAddress());
            orderInfo.setSendPerson(sendAddress.getContactPerson());
            orderInfo.setSendMobile(sendAddress.getContactMobile());
        }
        //收货地址
        String receiveAddressId = request.getReceiveAddressId();
        MemberAddress receiveAddress = this.addressService.getAddress(receiveAddressId, memberId, AddressType.Receive);
        orderInfo.setReceiveProvinceId(receiveAddress.getProvinceId());
        orderInfo.setReceiveProvinceName(receiveAddress.getProvinceName());
        orderInfo.setReceiveCityId(receiveAddress.getCityId());
        orderInfo.setReceiveCityName(receiveAddress.getCityName());
        orderInfo.setReceiveCountyId(receiveAddress.getCountyId());
        orderInfo.setReceiveCountyName(receiveAddress.getCountyName());
        orderInfo.setReceiveTownId(receiveAddress.getTownId());
        orderInfo.setReceiveTownName(receiveAddress.getTownName());
        orderInfo.setReceiveAddress(receiveAddress.getDetailedAddress());
        orderInfo.setReceivePerson(receiveAddress.getContactPerson());
        orderInfo.setReceiveMobile(receiveAddress.getContactMobile());
        //消息
        orderInfo.setLeaveMsg(request.getLeaveMsg());//客户留言
        orderInfo.setRefundMsg(null);//退款原因
        orderInfo.setServiceFlag(null);//客服标记
        //签收完成
        orderInfo.setPointRecordId(null);//完成订单积分流水
        orderInfo.setCashRecordId(null);//给邀请人返现流水
        orderInfo.setMissionRecordId(null);
        orderInfo.setCompleteTime(null);
        orderInfo.setReturnDeadlineTime(null);
        orderInfo.setSettleTime(null);
        //状态
        orderInfo.setAfterSales(YNEnum.N.name());//是否售后
        orderInfo.setState(orderState.name());//状态
        orderInfo.setOrderTime(DateUtils.now());//下单时间
        orderInfo.beforeInsert();
        int orderInfoNum = this.orderInfoDao.insert(orderInfo);
        if (orderInfoNum != 1)
            throw new BusinessException(ErrorCode.ERROR_SERVER, "订单表记录入库失败");
        //新增订单操作记录
        OrderRecord orderRecord = new OrderRecord();
        orderRecord.setId(RandomUtils.randomUUID());
        orderRecord.setOrderId(orderId);
        orderRecord.setPrevState(null);
        orderRecord.setState(orderState.name());
        orderRecord.setReason("提交订单");
        orderRecord.setOperator(memberId);
        orderRecord.beforeInsert();
        int orderRecordNum = this.orderRecordDao.insert(orderRecord);
        if (orderRecordNum != 1) {
            throw new BusinessException(ErrorCode.ERROR_SERVER, "订单操作表记录入库失败");
        }
        //返回
        OrderCommitResponse orderCommitResponse = new OrderCommitResponse();
        orderCommitResponse.setId(orderId);
        orderCommitResponse.setPayChannel(userAuth.getChannel().getPayChannel());
        orderCommitResponse.setPayTradeNoPre(payTradeNoPre);
        orderCommitResponse.setPayAmount(orderInfo.getPayAmount());
        orderCommitResponse.setState(orderState);
        orderCommitResponse.setPayArgs(payArgs);
        return orderCommitResponse;
    }

    //取消订单
    @Transactional
    public void cancelOrder(String orderId) {
        //查询订单信息
        final OrderInfo orderInfo = this.getOrderInfoByState(orderId, OrderState.ToPay);
        final PayChannel payChannel = Convert.toType(orderInfo.getPayChannel(), PayChannel.class);
        if (payChannel == null)
            throw new BusinessException(ErrorCode.ERROR_SERVER, "支付渠道异常");
        switch (payChannel) {
            case WeChatPay:
                //支付中的不能关闭
                if (this.weChatService.isPayingOrPaid(orderId))
                    throw new BusinessException(ErrorCode.ERROR_SERVER, "支付中不能取消");
                //先关闭线上订单
                this.weChatService.closeOrder(orderId);
                break;
            case AliPay:
                throw new BusinessException(ErrorCode.ERROR_SERVER, "不支持的渠道,敬请期待");
            default:
                throw new BusinessException(ErrorCode.ERROR_SERVER, "不支持的渠道");
        }
        //解锁商品库存
        List<OrderGoods> orderGoodsList = this.getOrderGoodsList(orderId);
        for (OrderGoods orderGoods : orderGoodsList)
            this.stockService.unlockStock(orderGoods, "用户取消订单或订单超时未支付");
        //返还代金券
        List<OrderCoupon> orderCouponList = this.getOrderCouponList(orderId);
        for (OrderCoupon orderCoupon : orderCouponList)
            this.couponService.returnCoupon(orderInfo.getMemberId(), orderCoupon.getCouponId(), orderId);
        //修改订单状态
        final Example updateOrderExample = new Example(OrderInfo.class);
        updateOrderExample.createCriteria().andEqualTo(OrderInfo.ID, orderId)
                .andEqualTo(OrderInfo.STATE, OrderState.ToPay.name());
        OrderInfo orderInfoUpdate = new OrderInfo();
        orderInfoUpdate.setState(OrderState.Closed.name());
        orderInfoUpdate.beforeUpdate();
        int orderUpdateNum = this.orderInfoDao.updateByExampleSelective(orderInfoUpdate, updateOrderExample);
        if (orderUpdateNum != 1) {
            this.log.error(String.format("更新订单表状态由%s到%s失败", OrderState.ToPay.name(), OrderState.Closed.name()));
            throw new BusinessException(ErrorCode.ERROR_SERVER, "更新订单表状态失败");
        }
        //新增订单操作记录日志
        OrderRecord orderRecord = new OrderRecord();
        orderRecord.setId(RandomUtils.randomUUID());
        orderRecord.setOrderId(orderId);
        orderRecord.setPrevState(OrderState.ToPay.name());
        orderRecord.setState(OrderState.Closed.name());
        orderRecord.setReason("用户或客服取消订单或订单超时未支付");
        orderRecord.setOperator("用户或客服");
        orderRecord.beforeInsert();
        this.orderRecordDao.insert(orderRecord);
    }

    //支付订单,只提供给 PayService 使用
    @Transactional
    public void payOrder(PayOrderBean payOrderBean) {
        //验证参数
        Assert.notNull(payOrderBean, "payOrderBean can not be null");
        payOrderBean.assertValid();
        //查询 order_info 表
        this.log.info("支付回调: " + payOrderBean.toString());
        final String orderId = payOrderBean.getOrderId();
        OrderInfo orderInfo = this.getOrderInfoByState(orderId, OrderState.ToPay);
        //支付渠道验证
        if (payOrderBean.getPayChannel() != Convert.toType(orderInfo.getPayChannel(), PayChannel.class)) {
            final String msg = String.format("orderId:%s 实际支付渠道:%s 应支付渠道:%s", orderId, payOrderBean.getPayChannel(), orderInfo.getPayChannel());
            this.log.error(msg);
            BugReportUtils.sendAsync(BugReportLevel.ERROR, msg);
            throw new BusinessException(ErrorCode.ERROR_SERVER, "支付渠道错误");
        }
        //支付人验证
        if (!StringUtils.equals(payOrderBean.getOpenid(), orderInfo.getPayOpenId())) {
            final String msg = String.format("orderId:%s 实际支付人:%s 应支付人:%s", orderId, payOrderBean.getOpenid(), orderInfo.getPayOpenId());
            this.log.error(msg);
            BugReportUtils.sendAsync(BugReportLevel.ERROR, msg);
            throw new BusinessException(ErrorCode.ERROR_SERVER, "支付人错误");
        }
        //金额验证
        if (payOrderBean.getAmount().compareTo(orderInfo.getPayAmount()) != 0) {
            final String msg = String.format("orderId:%s 实际支付:%s 应付:%s", orderId, payOrderBean.getAmount(), orderInfo.getPayAmount());
            this.log.error(msg);
            BugReportUtils.sendAsync(BugReportLevel.ERROR, msg);
            throw new BusinessException(ErrorCode.ERROR_SERVER, "实际支付金额与订单待支付金额不一致");
        }

        //修改 支付信息 订单状态 ToPay-> ToSend
        final Example updateOrderExample = new Example(OrderInfo.class);
        updateOrderExample.createCriteria().andEqualTo(OrderInfo.ID, orderId)
                .andEqualTo(OrderInfo.STATE, OrderState.ToPay.name());

        OrderInfo orderInfoUpdate = new OrderInfo();
        orderInfoUpdate.setPayTradeNo(payOrderBean.getPayTradeNo());
        orderInfoUpdate.setPayTime(payOrderBean.getPayTime());
        orderInfoUpdate.setPayFinished(YNEnum.Y.name());
        //状态
        orderInfoUpdate.setState(OrderState.ToSend.name());//
        orderInfoUpdate.beforeUpdate();
        final int updateOrderCount = this.orderInfoDao.updateByExampleSelective(orderInfoUpdate, updateOrderExample);
        if (updateOrderCount != 1) {
            this.log.warn("支付更新订单状态失败 orderId:" + orderId);
            throw new BusinessException(ErrorCode.ERROR_SERVER, "支付失败");
        }
        //新增订单操作记录日志
        OrderRecord orderRecord = new OrderRecord();
        orderRecord.setId(RandomUtils.randomUUID());
        orderRecord.setOrderId(orderId);
        orderRecord.setPrevState(OrderState.ToPay.name());
        orderRecord.setState(OrderState.ToSend.name());
        orderRecord.setReason("用户支付成功");
        orderRecord.setOperator("系统");
        orderRecord.beforeInsert();
        final int insert = this.orderRecordDao.insert(orderRecord);
        if (insert != 1) {
            this.log.warn("插入订单日志失败");
            throw new BusinessException(ErrorCode.ERROR_SERVER, "订单操作失败");
        }
        //pay_record 表 update finish 为 Y
        PayRecord payRecordUpdate = new PayRecord();
        payRecordUpdate.setId(payOrderBean.getPayTradeNo());
        payRecordUpdate.setFinish(YNEnum.Y.name());
        payRecordUpdate.beforeUpdate();
        final int updatePayRecordCount = this.payRecordDao.updateByPrimaryKeySelective(payRecordUpdate);
        if (updatePayRecordCount != 1) {
            this.log.warn("更新支付记录表 finish 为 Y 失败 orderId:" + orderId);
            throw new BusinessException(ErrorCode.ERROR_SERVER, "支付失败");
        }
        this.log.info("支付成功 orderId:" + orderId);
    }

    //发货,客服调用
    @Transactional
    public void sendOrder(OrderSendRequest request) {
        //验证参数
        String orderId = request.getOrderId();
        String expressId = request.getExpressId();
        String expressOrderId = request.getExpressOrderId();

        Assert.hasText(orderId, "orderId can not be empty");
        Assert.hasText(expressId, "expressId can not be empty");
        Assert.hasText(expressOrderId, "expressOrderId can not be empty");
        //查询订单
        this.getOrderInfoByState(orderId, OrderState.ToSend);
        //解锁库存,扣减库存  StockService. outStock
        List<OrderGoods> orderGoodsList = this.getOrderGoodsList(orderId);
        for (OrderGoods orderGoods : orderGoodsList) {
            this.stockService.outStock(orderGoods, "订单出库");
        }
        //修改 物流 express_id express_order_id 字段
        ExpressInfo expressInfo = this.expressInfoDao.selectByPrimaryKey(expressId);
        if (expressInfo == null) {
            throw new BusinessException(ErrorCode.ERROR_SERVER, "不支持的快递公司");
        }

        final Example updateOrderExample = new Example(OrderInfo.class);
        updateOrderExample.createCriteria().andEqualTo(OrderInfo.ID, orderId)
                .andEqualTo(OrderInfo.STATE, OrderState.ToSend.name());

        OrderInfo orderInfoUpdate = new OrderInfo();
        orderInfoUpdate.setState(OrderState.UnderWay.name());
        orderInfoUpdate.setSendTime(DateUtils.now());
        orderInfoUpdate.setExpressId(expressId);
        orderInfoUpdate.setExpressOrderId(expressOrderId);
        orderInfoUpdate.beforeUpdate();
        final int updateOrderCount = this.orderInfoDao.updateByExampleSelective(orderInfoUpdate, updateOrderExample);
        if (updateOrderCount != 1) {
            this.log.warn("发货失败 orderId:" + orderId);
            throw new BusinessException(ErrorCode.ERROR_SERVER, "发货失败");
        }
        //插入订单记录
        OrderRecord orderRecord = new OrderRecord();
        orderRecord.setId(RandomUtils.randomUUID());
        orderRecord.setOrderId(orderId);
        orderRecord.setPrevState(OrderState.ToSend.name());
        orderRecord.setState(OrderState.UnderWay.name());
        orderRecord.setReason("商家发货");
        orderRecord.setOperator("客服");
        orderRecord.beforeInsert();
        final int insert = this.orderRecordDao.insert(orderRecord);
        if (insert != 1) {
            this.log.warn("插入订单日志失败");
            throw new BusinessException(ErrorCode.ERROR_SERVER, "订单操作失败");
        }
    }

    //完成订单 签收(用户、调度任务调用)
    @Transactional
    public void signOrder(String orderId) {
        Assert.hasText(orderId, "orderId can not be empty");
        //查询订单 验证订单状态 UnderWay
        this.getOrderInfoByState(orderId, OrderState.UnderWay);

        //修改订单状态   UnderWay->Completed 更新签收时间、退货截止时间

        //计算退货截止时间
        Date completeTime = DateUtils.now();
        int returnDays = this.goodsSpuDao.getMinReturnDaysByOrderId(orderId);
        Date returnDeadLineTime = DateUtils.add(completeTime, returnDays, 0, 0, 0, 0);

        final Example updateOrderExample = new Example(OrderInfo.class);
        updateOrderExample.createCriteria().andEqualTo(OrderInfo.ID, orderId)
                .andEqualTo(OrderInfo.STATE, OrderState.UnderWay.name());

        OrderInfo orderInfoUpdate = new OrderInfo();
        orderInfoUpdate.setState(OrderState.Completed.name());
        orderInfoUpdate.setCompleteTime(completeTime);
        orderInfoUpdate.setReturnDeadlineTime(returnDeadLineTime);
        orderInfoUpdate.beforeUpdate();
        int orderUpdateNum = this.orderInfoDao.updateByExampleSelective(orderInfoUpdate, updateOrderExample);
        if (orderUpdateNum != 1) {
            this.log.error(String.format("更新订单表状态到%s失败", OrderState.Completed.name()));
            throw new BusinessException(ErrorCode.ERROR_SERVER, "更新订单表状态失败");
        }
        //订单记录
        OrderRecord orderRecord = new OrderRecord();
        orderRecord.setId(RandomUtils.randomUUID());
        orderRecord.setOrderId(orderId);
        orderRecord.setPrevState(OrderState.UnderWay.name());
        orderRecord.setState(OrderState.Completed.name());
        orderRecord.setReason("用户已经收货");
        orderRecord.setOperator("系统或用户签收");
        orderRecord.beforeInsert();
        final int insert = this.orderRecordDao.insert(orderRecord);
        if (insert != 1) {
            this.log.warn("插入订单日志失败");
            throw new BusinessException(ErrorCode.ERROR_SERVER, "订单操作失败");
        }
        //不支持退货,立即结算
        if (returnDays <= 0) {
            this.log.info("该订单有商品不支持退货,立即结算");
            this.settle(orderId);
        }
    }

    //过了退货时间后，开始结算，新增积分，新增现金激励，更新store_info购买的商品，增加团队任务金额更新结算状态和结算日期
    @Transactional
    public void settle(String orderId) {
        Assert.hasText(orderId, "orderId can not be empty");
        //更新订单结算状态、结算时间,防止并发
        final OrderInfo orderInfoUpdate = new OrderInfo();
        orderInfoUpdate.setState(OrderState.Settled.name());
        orderInfoUpdate.setSettleTime(DateUtils.now());
        orderInfoUpdate.beforeUpdate();
        final Example updateOrderExample = new Example(OrderInfo.class);
        updateOrderExample.createCriteria().andEqualTo(OrderInfo.ID, orderId)
                .andEqualTo(OrderInfo.STATE, OrderState.Completed.name())
                .andLessThanOrEqualTo(OrderInfo.RETURN_DEADLINE_TIME, DateUtils.now());
        int count = this.orderInfoDao.updateByExampleSelective(orderInfoUpdate, updateOrderExample);
        if (count != 1) {
            this.log.warn("该订单已结算 orderId:" + orderId);
            return;
        }
        //查询订单
        final OrderInfo orderInfo = this.getOrderInfo(orderId);
        final List<OrderGoods> orderGoodsList = this.getOrderGoodsList(orderId);
        final boolean firstBuy = this.isFirstBuy(orderInfo.getMemberId());

        //给购买人增加积分--积分
        final int pointValue = firstBuy
                ? Math.max(this.configService.getFirstBuyMinPoint(), orderInfo.getPointValue())//首次购买积分如果不到100则加到100
                : orderInfo.getPointValue();
        final String pointRecordId = this.pointService.increasePoint(orderInfo.getMemberId(), pointValue, "订单结算", orderId);
        //给邀请人返现,首购发代金券--邀请,代金券,这个地方使用未加到 100 的积分
        final String cashRecordId = this.cashService.increaseRefMemberPointCashCoupon(orderInfo, orderGoodsList, firstBuy, orderInfo.getPointValue());
        //给用户增加商品可赚金额--可赚
        final String earnRecordId = this.cashService.increaseEarnCash(orderInfo, orderGoodsList, "订单结算");
        //增加团队任务激励--团队
        final String missionRecordId = this.missionService.increaseMission(orderInfo, orderGoodsList, "订单结算");
        //统计该订单的商品以及数量，入库member_hot_spu
        this.hotSpuService.increaseHotSpu(orderInfo, orderGoodsList);
        //购买人购买量统计
        this.storeService.increaseBuyInfo(orderInfo.getMemberId(), orderInfo.getItemCount(), orderInfo.getTotalOrderAmount(), orderInfo.getTotalMemberAmount(), orderInfo.getPayAmount());

        //保存关联信息到订单
        final OrderInfo orderInfoUpdateFinish = new OrderInfo();
        orderInfoUpdateFinish.setId(orderId);
        orderInfoUpdateFinish.setPointRecordId(pointRecordId);
        orderInfoUpdateFinish.setCashRecordId(cashRecordId);
        orderInfoUpdateFinish.setEarnRecordId(earnRecordId);
        orderInfoUpdateFinish.setMissionRecordId(missionRecordId);
        orderInfoUpdateFinish.beforeUpdate();
        int updateCount = this.orderInfoDao.updateByPrimaryKeySelective(orderInfoUpdateFinish);
        if (updateCount != 1) {
            this.log.warn("订单保存结算结果失败 orderId:" + orderInfo.getId());
            return;
        }

        //新增订单流水记录
        final OrderRecord orderRecord = new OrderRecord();
        orderRecord.setId(RandomUtils.randomUUID());
        orderRecord.setOrderId(orderId);
        orderRecord.setPrevState(OrderState.Completed.name());
        orderRecord.setState(OrderState.Settled.name());
        orderRecord.setReason("过了退货期，对该订单进行结算");
        orderRecord.setOperator("调度任务操作");
        orderRecord.beforeInsert();
        this.orderRecordDao.insert(orderRecord);
    }

    //申请退款
    @Transactional
    public void refundOrderRequest(String orderId, String refundReason, List<String> fileIdList) {
        //验证参数
        Assert.hasText(orderId, "orderId can not be empty");
        Assert.hasText(refundReason, "reason can not be empty");
        final UserAuth userAuth = this.getAuth();

        //查询订单,验证订单
        final OrderInfo orderInfo = this.getOrderInfoByState(orderId, OrderState.ToSend, OrderState.UnderWay, OrderState.Completed);
        final OrderState state = Convert.toType(orderInfo.getState(), OrderState.class);
        if (state == null)
            throw new BusinessException(ErrorCode.ERROR_SERVER, "订单状态异常,请刷新后重试");
        switch (state) {
            case ToSend: {
                if (Convert.toType(orderInfo.getPayFinished(), YNEnum.class) != YNEnum.Y) {//如果未支付过,直接取消订单
                    this.cancelOrder(orderId);
                    return;
                }
                //修改订单状态(Tosend--Refunding)
                this.modifyOrderState(orderId, state, OrderState.Refunding, false);
                //订单日志
                OrderRecord orderRecord = new OrderRecord();
                orderRecord.setId(RandomUtils.randomUUID());
                orderRecord.setOrderId(orderId);
                orderRecord.setPrevState(OrderState.ToSend.name());
                orderRecord.setState(OrderState.Refunding.name());
                orderRecord.setReason("用户申请退款(已支付待发货)");
                orderRecord.setOperator(userAuth.getMemberId());
                orderRecord.beforeInsert();
                final int insert = this.orderRecordDao.insert(orderRecord);
                if (insert != 1) {
                    this.log.warn("插入订单日志失败");
                    throw new BusinessException(ErrorCode.ERROR_SERVER, "订单操作失败");
                }
                break;
            }
            case UnderWay: {//如果订单状态为 UnderWay ->直接进入退货处理中
                //修改订单状态(UnderWay--Returning)
                this.modifyOrderState(orderId, state, OrderState.Returning, false);
                //新增订单操作记录日志
                OrderRecord orderRecord = new OrderRecord();
                orderRecord.setId(RandomUtils.randomUUID());
                orderRecord.setOrderId(orderId);
                orderRecord.setPrevState(OrderState.UnderWay.name());
                orderRecord.setState(OrderState.Returning.name());
                orderRecord.setReason("在途状态下用户申请退款");
                orderRecord.setOperator(userAuth.getMemberId());
                orderRecord.beforeInsert();
                final int insert = this.orderRecordDao.insert(orderRecord);
                if (insert != 1) {
                    this.log.warn("插入订单日志失败");
                    throw new BusinessException(ErrorCode.ERROR_SERVER, "订单操作失败");
                }
                break;
            }
            case Completed: {
                //如果结算状态为已结算，或者已经过了退款截止日期
                if (orderInfo.getReturnDeadlineTime() == null) {
                    this.log.error("退货截止时间为 null orderId:" + orderInfo.getId());
                    throw new BusinessException(ErrorCode.ERROR_SERVER, "申请退货失败, 请联系客服");
                }

                boolean isReturnDeadLine = DateUtils.now().compareTo(orderInfo.getReturnDeadlineTime()) > 0;
                if (isReturnDeadLine)
                    throw new BusinessException(ErrorCode.ERROR_SERVER, "已过最后退货期限, 不能退款");

                //如果订单状态 为 Completed ->售后标记 进入退货处理中
                //修改订单状态(Completed--Returning)
                this.modifyOrderState(orderId, state, OrderState.Returning, true);
                //新增订单操作记录日志
                OrderRecord orderRecord = new OrderRecord();
                orderRecord.setId(RandomUtils.randomUUID());
                orderRecord.setOrderId(orderId);
                orderRecord.setPrevState(OrderState.Completed.name());
                orderRecord.setState(OrderState.Returning.name());
                orderRecord.setReason("签收后用户申请退款");
                orderRecord.setOperator(userAuth.getMemberId());
                orderRecord.beforeInsert();
                final int insert = this.orderRecordDao.insert(orderRecord);
                if (insert != 1) {
                    this.log.warn("插入订单日志失败");
                    throw new BusinessException(ErrorCode.ERROR_SERVER, "订单操作失败");
                }
                break;
            }
            default:
                throw new BusinessException(ErrorCode.ERROR_SERVER, "状态错误");
        }
        this.saveRefundFileList(orderId, fileIdList);
    }

    //拒绝退货
    @Transactional
    public void rejectReturn(String orderId) {
        //验证参数
        Assert.hasText(orderId, "orderId can not be empty");
        //查询订单,验证订单状态
        this.getOrderInfoByState(orderId, OrderState.Returning);
        //修改订单状态(Returning--ReturnRej)
        this.modifyOrderState(orderId, OrderState.Returning, OrderState.ReturnRej, false);
        //新增订单操作记录日志
        OrderRecord orderRecord = new OrderRecord();
        orderRecord.setId(RandomUtils.randomUUID());
        orderRecord.setOrderId(orderId);
        orderRecord.setPrevState(OrderState.Returning.name());
        orderRecord.setState(OrderState.ReturnRej.name());
        orderRecord.setReason("客服拒绝退货");
        orderRecord.setOperator("客服");
        orderRecord.beforeInsert();
        final int insert = this.orderRecordDao.insert(orderRecord);
        if (insert != 1) {
            this.log.warn("插入订单日志失败");
            throw new BusinessException(ErrorCode.ERROR_SERVER, "订单操作失败");
        }
    }

    //同意退货
    @Transactional
    public void agreeReturn(String orderId) {
        //验证参数
        Assert.hasText(orderId, "orderId can not be empty");
        //查询订单,验证订单状态 Returning ReturnRej
        OrderInfo orderInfo = this.getOrderInfoByState(orderId, OrderState.Returning, OrderState.RefundRej);
        //修改状态  到 Refunding
        OrderState state = Convert.toType(orderInfo.getState(), OrderState.class);
        this.modifyOrderState(orderId, state, OrderState.Refunding, false);
        //新增订单操作记录日志
        OrderRecord orderRecord = new OrderRecord();
        orderRecord.setId(RandomUtils.randomUUID());
        orderRecord.setOrderId(orderId);
        orderRecord.setPrevState(orderInfo.getState());
        orderRecord.setState(OrderState.Refunding.name());
        orderRecord.setReason("客服同意退货");
        orderRecord.setOperator("客服");
        orderRecord.beforeInsert();
        final int insert = this.orderRecordDao.insert(orderRecord);
        if (insert != 1) {
            this.log.warn("插入订单日志失败");
            throw new BusinessException(ErrorCode.ERROR_SERVER, "订单操作失败");
        }
    }

    //拒绝退款
    @Transactional
    public void rejectRefund(String orderId) {
        //验证参数
        Assert.hasText(orderId, "orderId can not be empty");
        //查询订单,验证订单状态 Refunding
        this.getOrderInfoByState(orderId, OrderState.Refunding);
        //修改订单状态(Refunding--RefundRej)
        this.modifyOrderState(orderId, OrderState.Refunding, OrderState.RefundRej, false);
        //新增订单操作记录日志
        OrderRecord orderRecord = new OrderRecord();
        orderRecord.setId(RandomUtils.randomUUID());
        orderRecord.setOrderId(orderId);
        orderRecord.setPrevState(OrderState.Refunding.name());
        orderRecord.setState(OrderState.RefundRej.name());
        orderRecord.setReason("客服拒绝退款");
        orderRecord.setOperator("客服");
        orderRecord.beforeInsert();
        final int insert = this.orderRecordDao.insert(orderRecord);
        if (insert != 1) {
            this.log.warn("插入订单日志失败");
            throw new BusinessException(ErrorCode.ERROR_SERVER, "订单操作失败");
        }
    }

    //同意退款
    @Transactional
    public void agreeRefund(String orderId, String memberId) {
        //验证参数
        Assert.hasText(orderId, "orderId can not be empty");

        //查询订单,验证状态 Refunding RefundRej
        OrderInfo orderInfo = this.getOrderInfoByState(orderId, OrderState.Refunding, OrderState.RefundRej);
        OrderState state = Convert.toType(orderInfo.getState(), OrderState.class);
        //解锁库存,库存日志
        //返还代金券,日志
        //解锁商品库存
        final List<OrderGoods> orderGoodsList = this.getOrderGoodsList(orderId);
        for (OrderGoods orderGoods : orderGoodsList) {
            StockLock stockLock = this.stockLockDao.selectByPrimaryKey(orderGoods.getLockId());
            if (stockLock != null)
                this.stockService.unlockStock(orderGoods, "客服同意退款");
        }
        //查询该订单使用的代金券
        List<OrderCoupon> orderCouponList = this.getOrderCouponList(orderId);
        //返还代金券
        for (OrderCoupon orderCoupon : orderCouponList)
            this.couponService.returnCoupon(memberId, orderCoupon.getCouponId(), orderId);
        //状态 Refunding或RefundRej--Refunded
        this.modifyOrderState(orderId, state, OrderState.Refunded, false);
        //新增订单操作记录日志
        OrderRecord orderRecord = new OrderRecord();
        orderRecord.setId(RandomUtils.randomUUID());
        orderRecord.setOrderId(orderId);
        orderRecord.setPrevState(orderInfo.getState());
        orderRecord.setState(OrderState.Refunded.name());
        orderRecord.setReason("客服同意退款");
        orderRecord.setOperator("客服");
        orderRecord.beforeInsert();
        final int insert = this.orderRecordDao.insert(orderRecord);
        if (insert != 1) {
            this.log.warn("插入订单日志失败");
            throw new BusinessException(ErrorCode.ERROR_SERVER, "订单操作失败");
        }
    }

    //查询订单列表
    public PageableResponse<OrderListResponse> getOrderList(OrderListRequest request) {
        final UserAuth userAuth = this.getAuth();
        List<OrderListResponse> orderList = this.orderInfoDao.getOrderList(userAuth.getMemberId(), request.getOrderStateList(), request.toRowBounds());
        for (OrderListResponse order : orderList) {
            order.setStateText(order.getState().getText());
            if (order.getState() != OrderState.ToPay)
                continue;
            if (userAuth.getChannel() == null)
                continue;
            switch (userAuth.getChannel()) {
                case WeChat:
                    order.setPayArgs(this.weChatService.signPay(order.getPayTradeNoPre()));
                    break;
                case AliPay:
                    throw new BusinessException(ErrorCode.ERROR_SERVER, "不支持的渠道,敬请期待");
                default:
                    throw new BusinessException(ErrorCode.ERROR_SERVER, "不支持的渠道");
            }
        }
        return PageableResponse.create(orderList);
    }

    //查询订单详情
    public OrderDetailResponse getOrderDetail(String orderId) {
        OrderDetailResponse orderInfo = this.orderInfoDao.getOrderDetail(orderId);
        if (orderInfo == null)
            throw new BusinessException(ErrorCode.ERROR_SERVER, "无效的订单");
        //设置状态名
        orderInfo.setStateText(orderInfo.getState().getText());
        //设置支付参数
        if (orderInfo.getState() == OrderState.ToPay) {
            if (orderInfo.getPayChannel() == null)
                throw new BusinessException(ErrorCode.ERROR_SERVER, "支付方式为空,请联系客服");
            switch (orderInfo.getPayChannel()) {
                case WeChatPay:
                    final boolean paySuccess = this.weChatService.queryOrder(orderId);
                    if (paySuccess)
                        return this.getOrderDetail(orderId);
                    orderInfo.setPayArgs(this.weChatService.signPay(orderInfo.getPayTradeNoPre()));
                    break;
                case AliPay:
                    throw new BusinessException(ErrorCode.ERROR_SERVER, "不支持的支付渠道,敬请期待");
                default:
                    throw new BusinessException(ErrorCode.ERROR_SERVER, "不支持的支付渠道");
            }
        }
        //商品列表
        final List<OrderDetailResponseItem> orderGoodsList = this.orderInfoDao.getOrderGoodsList(orderId);
        orderInfo.setSkuList(orderGoodsList);
        return orderInfo;
    }

    //查询已完成、未结算、超过退款时间的订单
    public List<String> getToSettleOrderIdList() {
        return this.orderInfoDao.getToSettleOrderIdList();
    }

    //查询超时未支付的订单的id
    public List<String> getExpiredOrderIdList() {
        return this.orderInfoDao.getExpiredOrderIdList(this.orderProperties.getPayExpireMinutes());
    }
}
